package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;


/**
 * Does the communication with a sincle Auction-Client
 * @author Andreas Mair
 *
 */
class TCPServerThread
implements Runnable
{
	private BufferedReader brIn;
	private PrintWriter out= null;
	private Socket clientSocket = null;
	private User user;
	
	//User-Commands
	private static String COMM_LOGIN="!login";
	private static String COMM_LIST="!list";
	private static String COMM_LOGOUT="!logout";
	//Auction-Commands
	private static String COMM_CREATE="!create";
	private static String COMM_BID="!bid";
	private static String COMM_END="!end";
	
	private static String OUT_SUCCESSFULLY_LOGGED_IN="!logged-in";
	private static String OUT_SUCCESSFULLY_LOGGED_OUT="!logged-out";
	
	
	public TCPServerThread(Socket clientSocket) 
	{
		this.clientSocket = clientSocket;
	}

  public void run() 
  {
	    try 
	    {
	    	System.out.println("Running tcpserverthread");
	    	out = new PrintWriter(clientSocket.getOutputStream(), true);
	    	brIn=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
	        user=null;
	        String strLine;
	        
	        while((strLine=brIn.readLine())!=null)
	        {
	        	String strParts[]=strLine.split(" ");
	        	if(strParts[0].equals(COMM_LOGIN))
	        	{
	        		login(strParts);
	        	}
	        	else if(strParts[0].equals(COMM_LIST))
	        	{
	        		out.println(AuctionManager.getInstance().list());
	        	}
	        	else if(strParts[0].equals(COMM_END))
	        	{
	        		stop();
	        	}	        	
	        	else if(user==null &&(strParts[0].equals(COMM_LOGOUT) || strParts[0].equals(COMM_CREATE) || 
	        			strParts[0].equals(COMM_BID)))
	        	{
	        		out.println("You have to login first!");
	        	}	
	        	else if(strParts[0].equals(COMM_LOGOUT))
	        	{
	        		logout();
	        	}
	        	else if(strParts[0].equals(COMM_CREATE))
	        	{
	        		createAuction(strParts);
	        	}
	        	else if(strParts[0].equals(COMM_BID))
	        	{
	        		bidOnAuction(strParts);
	        	}	
	        	else
	        	{
	        		out.println("Unknown Command!");
	        	}
	        }
	    }
	    catch (IOException e) 
	    {
	    	System.out.println("IOException occured while listening for Client-Messages "+e.getMessage());
	    }
	    stop();
		System.out.println("TCPServerThread stops...");
  	}
  
  /**
   * Stops the current TCPServerThread, closes the Sockets and logs the User out
   */
  private void stop()
  {
      try 
      {
			brIn.close();
	        out.close();
	        clientSocket.close();
	        if(user!=null)
	        {
	        	UserManager.getInstance().logout(user.getStrName(), user.getIAClientAddress(), user.getiPClientPort());
	        }
		}
      catch (IOException e) 
      {
      	//ignore
      }	  
  }
  
  /**
   * Logs a User in
   * @param strLine contains out of command, username and udp-port
   */
  private void login(String [] strLine)
  {
		if(user!=null)
		{
			out.println(user.getStrName()+" is already logged in on this client!");
		}
		else
		{
			try
			{
				String strUser=strLine[1];
				int udpport=Integer.parseInt(strLine[2]);
				if((user=UserManager.getInstance().login(strUser,clientSocket.getInetAddress(),udpport))!=null)
				{
					out.println(OUT_SUCCESSFULLY_LOGGED_IN+ strUser);
					UserManager.getInstance().sendNotifications(user);
				}
				else
				{
					out.println(strUser+" is already logged in somewhere!");
				}
			}
			catch(IndexOutOfBoundsException ex)
			{
				out.println("Invalid parameters, Usage: !login <username>!");
			}
			catch(NumberFormatException nex)
			{
				out.println("Invalid parameters, error parsing the udp-Port!");
			} 
		}
  }
  
  /**
   * Logs the current User out
   * @param strLine contains out of command, username and udp-port
   */  
  private void logout()
  {
	  if(UserManager.getInstance().logout(user.getStrName(), user.getIAClientAddress(), user.getiPClientPort())==null)
	  {
		  //should never be reached
		  out.println("You have to log in first!"); 
	  }
	  else
	  {
		  out.println(OUT_SUCCESSFULLY_LOGGED_OUT+ user.getStrName());
		  this.user=null;
	  }
  }

  /**
   * Creates a new Auction
   * @param strLine contains out of command, auction runtime in seconds and auction description
   */
  private void createAuction(String []strLine)
  {
	  try
	  {
		  long lTime=Long.parseLong(strLine[1]);
		  String strDescription=strLine[2];
		  for(int i=3;i<strLine.length;i++)
		  {
			  strDescription+=" "+strLine[i];
		  }
		  
		  if(strDescription.length()==0)
		  {
			  out.println("You have to give the auction a description!");
		  }
		  else
		  {
			  Auction auction=AuctionManager.getInstance().create(lTime,strDescription,user);
			  if(auction!=null)
			  {
				  out.println("An auction '"+auction.getStrDesc()+"' with id "+auction.getiId()+" has been created "+
						  "and will end on "+AuctionManager.getInstance().formatDate(auction.getdEnd())+".");
			  }
	  }
	  }catch (IndexOutOfBoundsException iox)
	  {
		  out.println("Invalid parameters, Usage: !create <duration> <description>!");
	  }
	  catch(NumberFormatException nex)
	  {
		  out.println("Invalid parameters, the first parameter (the duration in seconds) has to be a number!");
	  } 
  }
  
  /**
   * Bids on a existing Auction
   * @param strLine contains out of command, Auction id and Amount to bid
   */  
  private void bidOnAuction(String []strLine)
  {
	  try
	  {
		  int iNumber=Integer.parseInt(strLine[1]);
		  
		  Double dValue=Double.parseDouble(strLine[2]);
		  long lPrice=(long)(dValue*100);

		  Auction auction=AuctionManager.getInstance().bid(iNumber,lPrice,user);
		  if(auction!=null)
		  {
			  if(auction.getuHighest().getStrName().equals(user.getStrName()) && auction.getlPrice()==lPrice)
			  {
				  out.println("You successfully bid with "+AuctionManager.getInstance().formatLong(lPrice)+" on '"+auction.getStrDesc()+"'.");
			  }
			  else
			  {
				  out.println("You unsuccessfully bid with "+AuctionManager.getInstance().formatLong(lPrice)+" on '"+auction.getStrDesc()+
						  "'. Current highest bid is "+AuctionManager.getInstance().formatLong(auction.getlPrice())+".");
			  }					  
		  }
		  else
		  {
			  out.println("Auction-id '"+iNumber+"' does not exist!");
		  }
	  }catch (IndexOutOfBoundsException iox)
	  {
		  out.println("Invalid parameters, Usage: !bid <auction-id> <amount>!");
	  }
	  catch(NumberFormatException nex)
	  {
		  out.println("Invalid parameters, both have to be numeric!");
	  }
  }
}
